package com.lzh.main.consumer;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lzh.main.mapper.UserMapper;
import com.lzh.main.pojo.entity.User;
import com.lzh.main.utils.JwtUtil;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@ServerEndpoint("/websocket/{token}")  // 注意不要以'/'结尾
public class WebSocketServer {
    private static final ConcurrentHashMap<Integer, WebSocketServer> users = new ConcurrentHashMap<>();
    // 房间管理相关映射表
    private static final ConcurrentHashMap<Integer, String> userRoomMap = new ConcurrentHashMap<>(); // 用户ID -> 房间ID
    private static final ConcurrentHashMap<String, Set<Integer>> roomUserMap = new ConcurrentHashMap<>(); // 房间ID -> 用户ID集合
    private static UserMapper userMapper;
    private static RestTemplate restTemplate;
    private User user;
    private Session session = null;

    // 创建对手
    private static JSONObject createOpponent(User user) {
        JSONObject opponent = new JSONObject();
        opponent.put("userId", user.getId());
        opponent.put("username", user.getUsername());
        opponent.put("photo", user.getPhoto());
        opponent.put("rating", user.getRating());
        return opponent;
    }

    private static void sendOpponents(User current, User opp1, User opp2, String roomId) {
        JSONObject response = new JSONObject();
        response.put("event", "matching-success");
        JSONArray opponents = new JSONArray();
        opponents.add(createOpponent(opp1));
        opponents.add(createOpponent(opp2));
        response.put("opponents", opponents);
        response.put("roomId", roomId);
        users.get(current.getId()).sendMessage(response.toJSONString());
        System.out.println("sendOpponents: " + response.toJSONString());
    }

    public static void startGame(Integer aId, Integer bId, Integer cId) {
        User a = userMapper.selectById(aId);
        User b = userMapper.selectById(bId);
        User c = userMapper.selectById(cId);

        String roomId = UUID.randomUUID().toString();
        System.out.println("创建房间: " + roomId);

        // 维护用户和房间的映射关系
        userRoomMap.put(a.getId(), roomId);
        userRoomMap.put(b.getId(), roomId);
        userRoomMap.put(c.getId(), roomId);

        // 维护房间和用户的映射关系
        Set<Integer> roomUsers = new CopyOnWriteArraySet<>();
        roomUsers.add(a.getId());
        roomUsers.add(b.getId());
        roomUsers.add(c.getId());
        roomUserMap.put(roomId, roomUsers);

        //为每个用户生成对手信息
        sendOpponents(a, b, c, roomId);
        sendOpponents(b, a, c, roomId);
        sendOpponents(c, a, b, roomId);
    }

    @Autowired
    public void setUserMapper(UserMapper userMapper) {
        WebSocketServer.userMapper = userMapper;
    }

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        WebSocketServer.restTemplate = restTemplate;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        // 建立连接时自动调用
        this.session = session;
        System.out.println("连接成功!");
        int userId = JwtUtil.getUserId(token);
        this.user = userMapper.selectById(userId);
        if (this.user != null) {
            users.put(userId, this);
        } else {
            this.session.close();
        }
        // 输出当前在线用户
        System.out.println("当前在线用户: " + users.keySet().stream()
                .map(id -> id + ":" + users.get(id).user.getUsername())
                .collect(java.util.stream.Collectors.joining(", ")));
    }

    @OnClose
    public void onClose() {
        // 关闭链接时自动调用
        System.out.println("断开连接");
        if (this.user != null) {
            users.remove(this.user.getId());
        }
        // 输出当前在线用户
        System.out.println("当前在线用户: " + users.keySet().stream()
                .map(id -> id + ":" + users.get(id).user.getUsername())
                .collect(java.util.stream.Collectors.joining(", ")));
    }

    private void startMatching() {
        System.out.println(this.user.getUsername() + "开始匹配");
        MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
        data.add("userId", this.user.getId().toString());
        data.add("rating", this.user.getRating().toString());
        restTemplate.postForObject("http://127.0.0.1:8081/api/player/add/", data, String.class);
    }

    private void stopMatching() {
        System.out.println(this.user.getUsername() + "停止匹配");

        // 如果用户在房间中，移除房间映射
        String roomId = userRoomMap.get(this.user.getId());
        if (roomId != null) {
            userRoomMap.remove(this.user.getId());
            // 从房间用户集合中移除该用户
            Set<Integer> roomUsers = roomUserMap.get(roomId);
            if (roomUsers != null) {
                roomUsers.remove(this.user.getId());
                // 如果房间空了，删除房间
                if (roomUsers.isEmpty()) {
                    roomUserMap.remove(roomId);
                }
            }
        }

        MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
        data.add("userId", this.user.getId().toString());
        restTemplate.postForObject("http://127.0.0.1:8081/api/player/remove/", data, String.class);
    }

    // 处理移动消息
    private void handleMove(JSONObject data) {
        try {
            String roomId = data.getString("roomId");
            if (roomId == null) {
                System.out.println("房间ID为空");
                return;
            }
            // 获取发送消息的玩家Id
            int playerId = data.getIntValue("userId");

            // 验证此用户是否在该房间
            String userRoom = userRoomMap.get(playerId);
            if (userRoom == null || !userRoom.equals(roomId)) {
                System.out.println("用户 " + playerId + " 不在房间 " + roomId + " 中，拒绝处理移动消息");
                return;
            }

            // 获取房间内所有用户
            Set<Integer> roomUsers = roomUserMap.get(roomId);
            if (roomUsers == null || roomUsers.isEmpty()) {
                System.out.println("房间 " + roomId + " 不存在或为空");
                return;
            }

            System.out.println("处理用户 " + playerId + " 在房间 " + roomId + " 中的移动消息");
            System.out.println("房间内所有用户: " + roomUsers);

            JSONObject moveData = new JSONObject();
            moveData.put("event", "move");
            moveData.put("roomId", data.getString("roomId"));
            moveData.put("userId", data.getInteger("userId"));
            moveData.put("tx", data.getDoubleValue("tx"));
            moveData.put("ty", data.getDoubleValue("ty"));
            moveData.put("x", data.getDoubleValue("x"));
            moveData.put("y", data.getDoubleValue("y"));

            // 广播移动消息给房间内的其他用户
            int broadcastCount = 0;
            for (Integer userId : roomUsers) {
                if (userId != playerId && users.containsKey(userId)) {  // 不发送给自己
                    WebSocketServer receiver = users.get(userId);
                    if (receiver != null) {
                        receiver.sendMessage(data.toJSONString());
                        broadcastCount++;
                        System.out.println("后端发送移动信息: " + moveData.toJSONString());
                    }
                }
            }

            System.out.println("移动消息已广播给 " + broadcastCount + " 个用户");
        } catch (Exception e) {
            System.out.println("处理移动消息时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 处理火球
    private void handleFireBall(JSONObject data) {
        try {
            String roomId = data.getString("roomId");
            if (roomId == null) {
                System.out.println("房间ID为空");
                return;
            }
            // 获取发送消息的玩家Id
            int playerId = data.getIntValue("userId");

            // 验证此用户是否在该房间
            String userRoom = userRoomMap.get(playerId);
            if (userRoom == null || !userRoom.equals(roomId)) {
                System.out.println("用户 " + playerId + " 不在房间 " + roomId + " 中，拒绝处理移动消息");
                return;
            }

            // 获取房间内所有用户
            Set<Integer> roomUsers = roomUserMap.get(roomId);
            if (roomUsers == null || roomUsers.isEmpty()) {
                System.out.println("房间 " + roomId + " 不存在或为空");
                return;
            }

            System.out.println("处理用户 " + playerId + " 在房间 " + roomId + " 中的移动消息");
            System.out.println("房间内所有用户: " + roomUsers);

            // 广播移动消息给房间内的其他用户
            int broadcastCount = 0;
            for (Integer userId : roomUsers) {
                if (userId != playerId && users.containsKey(userId)) {  // 不发送给自己
                    WebSocketServer receiver = users.get(userId);
                    if (receiver != null) {
                        // 使用原始数据发送消息，确保事件名称一致
                        receiver.sendMessage(data.toJSONString());
                        broadcastCount++;
                        System.out.println("后端发送火球信息: " + data.toJSONString());
                    }
                }
            }

            System.out.println("移动消息已广播给 " + broadcastCount + " 个用户");
        } catch (Exception e) {
            System.out.println("处理移动消息时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 处理闪现
    private void handleFlash(JSONObject data) {
        try {
            String roomId = data.getString("roomId");
            if (roomId == null) {
                System.out.println("房间ID为空");
                return;
            }
            // 获取发送消息的玩家Id
            int playerId = data.getIntValue("userId");

            // 验证此用户是否在该房间
            String userRoom = userRoomMap.get(playerId);
            if (userRoom == null || !userRoom.equals(roomId)) {
                System.out.println("用户 " + playerId + " 不在房间 " + roomId + " 中，拒绝处理闪现消息");
                return;
            }

            // 获取房间内所有用户
            Set<Integer> roomUsers = roomUserMap.get(roomId);
            if (roomUsers == null || roomUsers.isEmpty()) {
                System.out.println("房间 " + roomId + " 不存在或为空");
                return;
            }

            System.out.println("处理用户 " + playerId + " 在房间 " + roomId + " 中的闪现消息");
            System.out.println("房间内所有用户: " + roomUsers);

            // 广播闪现消息给房间内的其他用户
            int broadcastCount = 0;
            for (Integer userId : roomUsers) {
                if (userId != playerId && users.containsKey(userId)) {  // 不发送给自己
                    WebSocketServer receiver = users.get(userId);
                    if (receiver != null) {
                        // 使用原始数据发送消息
                        receiver.sendMessage(data.toJSONString());
                        broadcastCount++;
                        System.out.println("后端发送闪现信息: " + data.toJSONString());
                    }
                }
            }

            System.out.println("闪现消息已广播给 " + broadcastCount + " 个用户");
        } catch (Exception e) {
            System.out.println("处理闪现消息时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 处理治疗
    private void handleHeal(JSONObject data) {
        try {
            String roomId = data.getString("roomId");
            if (roomId == null) return;

            int playerId = data.getIntValue("userId");
            String userRoom = userRoomMap.get(playerId);
            if (userRoom == null || !userRoom.equals(roomId)) return;

            Set<Integer> roomUsers = roomUserMap.get(roomId);
            if (roomUsers == null) return;

            System.out.println("处理用户 " + playerId + " 在房间 " + roomId + " 中的治疗消息");
            
            // 广播治疗消息给房间内的其他用户
            int broadcastCount = 0;
            for (Integer userId : roomUsers) {
                if (userId != playerId && users.containsKey(userId)) {
                    WebSocketServer receiver = users.get(userId);
                    if (receiver != null) {
                        // 使用原始数据发送消息
                        receiver.sendMessage(data.toJSONString());
                        broadcastCount++;
                        System.out.println("后端发送治疗信息: " + data.toJSONString());
                    }
                }
            }
            
            System.out.println("治疗消息已广播给 " + broadcastCount + " 个用户");
        } catch (Exception e) {
            System.out.println("处理治疗消息时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 处理聊天消息
    private void handleChatMessage(JSONObject data) {
        try {
            int senderId = data.getIntValue("senderId");
            int receiverId = data.getIntValue("receiverId");
            String content = data.getString("content");

            // 检查接收者是否在线
            WebSocketServer receiver = users.get(receiverId);
            if (receiver != null) {
                JSONObject message = new JSONObject();
                message.put("event", "chat_message");
                message.put("senderId", senderId);
                message.put("content", content);
                message.put("timestamp", System.currentTimeMillis());

                receiver.sendMessage(message.toJSONString());
                System.out.println("发送聊天消息给用户: " + receiverId);
            }
        } catch (Exception e) {
            System.out.println("处理聊天消息时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // Server从Client接收消息时触发
        JSONObject data = JSONObject.parseObject(message);
        System.out.println("接受信息 " + data);
        String event = data.getString("event");
        switch (event) {
            case "start-matching":
                startMatching();
                break;
            case "stop-matching":
                stopMatching();
                break;
            case "move":
                handleMove(data);
                break;
            case "shoot_fireball":
            case "fireball":
                handleFireBall(data);
                break;
            case "flash":
                handleFlash(data);
                break;
            case "heal":
                handleHeal(data);
                break;
            case "message_sent":
                handleChatMessage(data);
                break;
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendMessage(String message) {
        synchronized (this.session) {
            try {
                this.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}